package org.easy.eao.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 反射工具类
 * @author Frank
 */
public final class ReflectUtils {
	
	private ReflectUtils() {
		throw new IllegalAccessError("该类不允许实例化");
	}
	
	@SuppressWarnings("rawtypes")
	public static Parameter[] getParameter(Method method) {
		Class[] types = method.getParameterTypes();
		Parameter[] result = new Parameter[types.length];
		if (result.length == 0)
			return result;
		Annotation[][] a = method.getParameterAnnotations();
		for (int i = 0; i < types.length; i++) {
			result[i] = new Parameter(i, types[i], a[i]);
		}
		return result;
	}
	
	/**
	 * 检查一个方法是否具有泛型返回值
	 * @param method 被检查的方法
	 * @return
	 */
	public static boolean hasGenericReturnType(Method method) {
		Type type = method.getGenericReturnType();
		if (type instanceof Class<?>)
			return false;
		return true;
	}

	/**
	 * 获取泛型的最终实际类型
	 * @param actual 最终类型
	 * @param declared 泛型声明类型
	 * @param type 泛型名
	 * @return 返回泛型名所对应的最终类型
	 */
	public static Class<?> getActualGenericType(Class<?> actual, Class<?> declared, String type) {
		Map<String, Type> map = getActualTypeParametersMap(actual, declared);
		return (Class<?>) map.get(type);
	}

	/**
	 * 获取实际类参数的 Map
	 * @param actual 最终类
	 * @param generic 泛型声明类
	 * @return
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("rawtypes")
	private static Map<String, Type> getActualTypeParametersMap(Class<?> actual, Class<?> generic) {
		List<String> names = new ArrayList<String>();
		for (TypeVariable t : generic.getTypeParameters()) {
			names.add(t.getName());
		}
		
		List<Type> values = new ArrayList<Type>();
		for (Type t : actual.getGenericInterfaces()) {
			if (t instanceof Class<?>)
				continue;
			if (((ParameterizedType) t).getRawType().equals(generic)) {
				for (Type tt : ((ParameterizedType) t).getActualTypeArguments()) {
					values.add(tt);
				}
				break;
			}
		}
		if (values.size() == 0) {
			ParameterizedType type = (ParameterizedType) actual.getGenericSuperclass();
			if (type.getRawType().equals(generic)) {
				for (Type tt : ((ParameterizedType) type).getActualTypeArguments()) {
					values.add(tt);
				}
			}
		}
		
		Map<String, Type> result = new HashMap<String, Type>();
		for (int i = 0; i < names.size(); i++) {
			result.put(names.get(i), values.get(i));
		}
		return result;
	}
}
